	PAGE	,132			;AN000;
	TITLE	TREEPAR.SAL - PARSE THE DOS COMMAND LINE ;AN000;
;****************** START OF SPECIFICATIONS *****************************
; MODULE NAME: TREEPAR.SAL
;
; DESCRIPTIVE NAME: Handle the definition of the DOS command line parameters
;		    and the interface to the DOS system PARSER.
;
;FUNCTION: The static data areas are prescribed by the DOS system PARSER
;	   to define the several parameters presented to TREE.	These
;	   data areas are passed to the PARSER, and its responses checked
;	   to determine the nature of the user's specifications.  Any errors
;	   found in the user's parameters are defined in messages back
;	   to the user.
;
; ENTRY POINT: PARSER, near
;
; INPUT: (DOS COMMAND LINE PARAMETERS)
;
;	      [d:][path] TREE [D:][path] [/F] [/A]

;	 WHERE
;	      [d:][path] - Path where the TREE command resides.

;	      [D:][path] - Display of subdirectories starts with this
;			   specified subdirectory.  If this is not
;			   specified, the default is the drive root directory.

;	      [/F]	 - This requests the files in each subdirectory
;			   in addition to the subdirectories themselves
;			   are to be listed.
;
;	      [/A]	  -This requests use of alternate char in place of graphics.
;
;	Upon entry to PARSER in this module,
;	"CURRENT_PARM" = offset to start of parm text in command string
;	"ORDINAL" = initialized to zero
;	PSP+81H = text of DOS command line parms string

; EXIT-NORMAL: Carry flag is clear.

; EXIT-ERROR: Carry flag is set.  Parse error msg has been displayed.

; INTERNAL REFERENCES:
;    ROUTINES:
;	PARSE_ERROR:NEAR Display the appropriate Parse error message.

;    DATA AREAS:
;	The several parameter control blocks, defined by the System
;	PARSER interface, defining the TREE parameters.
;	INCLUDE PATHMAC.INC - PATHGEN MACRO

; EXTERNAL REFERENCES:
;    ROUTINES:
;	SENDMSG:NEAR	Uses Msg Descriptor to drive message handler.
;	SYSPARSE:NEAR	System Command Line Common Parser.
;
;    DATA AREAS:
;	EXITFL:BYTE	Errorlevel return code.
;	MSGNUM_PARSE:WORD Message descriptor for all parse errors.
;
; NOTES:
;	 This module should be processed with the SALUT preprocessor
;	 with the re-alignment not requested, as:
;
;		SALUT TREEPAR,NUL
;
;	 To assemble these modules, the alphabetical or sequential
;	 ordering of segments may be used.
;
;	 For LINK instructions, refer to the PROLOG of the main module,
;	 TREE.SAL.
;
;
;****************** END OF SPECIFICATIONS *****************************
	HEADER	<LOCAL MACROS, EQUATES> ;AN000;
	IF1				;AN000;
	    %OUT    COMPONENT=TREE, MODULE=TREEPAR.SAL... ;AN000;
	ENDIF				;AN000;
	INCLUDE PATHMAC.INC		;AN012;
; =  =	=  =  =  =  =  =  =  =	=  =
HEADER	MACRO	TEXT			;;AN000;
.XLIST					;;AN000;
	SUBTTL	&TEXT			;;AN000;
.LIST					;;AN000;
	PAGE				;;AN000;
	ENDM				;;AN000;
; =  =	=  =  =  =  =  =  =  =	=  =
	EXTRN	MAX_PATH:ABS		;AN000;MAX LENGTH OF PATH PERMITTED

;		      $SALUT (4,23,28,36) ;AN004;
MSG_DESC	      STRUC	   ;AN004;
MSG_NUM 	      DW   ?	   ;AN004;MESSAGE NUMBER (TO AX)
MSG_HANDLE	      DW   ?	   ;AN004;HANDLE OF OUTPUT DEVICE (TO BX)
MSG_SUBLIST	      DW   ?	   ;AN004;POINTER TO SUBLIST (TO SI)
MSG_COUNT	      DW   ?	   ;AN004;SUBSTITUTION COUNT (TO CX)
MSG_CLASS	      DW   ?	   ;AN004;MESSAGE CLASS (IN HIGH BYTE, TO DH)
				   ; LOW BYTE HAS 0 (FUNCTION "NO INPUT", TO DL);AN004;
MSG_DESC	      ENDS	   ;AN004;

ONE_SUBS	      EQU  1	   ;AN004;NUMBER OF VARIABLES

SUBLIST 	      STRUC	   ;AN000;
SUB_SIZE	      DB   ?	   ;AN004;SUBLIST SIZE (POINTER TO NEXT SUBLIST)
SUB_RES 	      DB   ?	   ;AN004;RESERVED
				   ;NEXT FIELD IS TO BE USED AS A DOUBLE WORD	   ;AN004;
SUB_VALUE	      DW   ?	   ;AN004;TIME, DATE, OR PTR TO DATA ITEM
SUB_VALUE_SEG	      DW   ?	   ;AN004;SEG ID OF PTR
				   ;(ABOVE FIELD MUST BE FILLED AT EXECUTION TIME  ;AN004;
				   ; IF THIS IS A .COM FILE)			   ;AN004;
SUB_ID		      DB   ?	   ;AN004;N OF %N
SUB_FLAGS	      DB   ?	   ;AN004;DATA TYPE FLAGS
SUB_MAX_WIDTH	      DB   ?	   ;AN004;MAXIMUM FIELD WIDTH (0=UNLIMITED)
SUB_MIN_WIDTH	      DB   ?	   ;AN004;MINIMUM FIELD WIDTH
SUB_PAD_CHAR	      DB   ?	   ;AN004;CHARACTER FOR PAD FIELD
				   ; CAN BE " ", "0" OR ",".			   ;AN004;
				   ; "," CAUSES INSERTION OF THE ACTIVE 	   ;AN004;
				   ; THOUSANDS SEPARATOR BETWEEN EVERY 3 DIGITS.   ;AN004;
SUBLIST 	      ENDS	   ;AN004;

;		LOCAL EQUATES

CMD_BUF_SIZE	      EQU  127	   ;AN000;NUMBER BYTES IN DOS COMMAND LINE BUFFER
ZERO		      EQU  0	   ;AN000;COMPARAND FOR CLEARED REG
COLON		      EQU  ":"	   ;AN000;FOLLOWS DRIVE LETTER IN FULL FILESPEC
NUL		      EQU  0	   ;AN000;DELIMITER FOR ASCIIZ STRINGS
BACK_SLASH	      EQU  "\"	   ;AN000;PATH DELIMITER
BLANK		      EQU  " "	   ;AN003;WIPE OUT SWITCH, AVOIDS DUPLICATES

;		EXIT CODES FROM SYSPARSE (WHEN CY=0)

SYSPRM_EX_OK	      EQU  0	   ;AN000; no error
SYSPRM_EX_MANY	      EQU  1	   ;AN000; too many operands
SYSPRM_EX_MISSING     EQU  2	   ;AN000; required operand missing
SYSPRM_EX_NOT_SWLIST  EQU  3	   ;AN000; not in switch list provided
SYSPRM_EX_NOT_KEYLIST EQU  4	   ;AN000; not in keyword list provided
SYSPRM_EX_RANGE       EQU  6	   ;AN000; out of range specified
SYSPRM_EX_VALUE       EQU  7	   ;AN000; not in value list provided
SYSPRM_EX_STRING      EQU  8	   ;AN000; not in string list provided
SYSPRM_EX_SYNTAX      EQU  9	   ;AN000; syntax error
SYSPRM_EX_EOL	      EQU  -1	   ;AN000; end of command line
		      HEADER <EXTRN REFERENCES, LOCAL VARIABLES> ;AN000;
		      EXTRN F_SWITCH:ABS ;AN000;BIT FLAGS TO TURN ON IF /F SPECIFIED

;	      $SALUT (4,15,20,28) ;AN000;
CSEG	      SEGMENT PARA PUBLIC 'CODE' ;AN000;
	      ASSUME CS:CSEG,DS:CSEG,ES:CSEG,SS:CSEG ;AN000;ESTABLISHED BY CALLER

;WHERE THE PARMS COME FROM:
	      EXTRN COMMAND:BYTE ;AN000;DOS INPUT COMMAND LINE PARMS

;WHERE THE PARMS GO:
	      EXTRN FLAGS:BYTE ;AN000;HAS INDICATOR FOR /F
			   ; WHERE F_SWITCH BIT GOES
	      EXTRN START_DRIVE:BYTE ;AN000;LETTER OF DRIVE BEING RESEARCHED
	      EXTRN START_PATH:BYTE ;AN000;PATH OF START OF CHAIN BEING RESEARCHED
	      EXTRN GRAF_TABLE:BYTE ;AN002;TABLE OF GRAPHIC CHARACTERS
	      EXTRN GRAF_TABLE_ALT:BYTE ;AN002;ALTERNATE SET OF GRAPHIC CHARACTERS

;MESSAGES USED:
	      EXTRN MSGNUM_PARSE:WORD ;AN000;MSG DESCRIPTOR FOR PARSE ERRORS
	      EXTRN SUBLIST_PARSE:WORD ;AN004;POINTS TO INVALID PARM
	      EXTRN MSGNUM_INVPATH:WORD ;AN000;"INVALID PATH" COMMON MESSAGE

;EXTERNAL SUBROUTINES USED:
	      EXTRN SYSPARSE:NEAR ;AN000;COMMAND LINE PARM PARSER
	      EXTRN SENDMSG:NEAR ;AN000;USES MSG DESCRIPTOR TO DRIVE MESSAGE HANDLR
	      EXTRN SCAN_DBCS:NEAR ;AN012;GET LAST TWO CHARS OF STRING

CURRENT_PARM  DW   ?	   ;AN000;POINTER INTO COMMAND OF NEXT OPERAND
	      PUBLIC CURRENT_PARM ;AN000;

ORDINAL       DW   ?	   ;AN000;ORDINAL NUMBER OF WHICH PARM TO PARSE
	      PUBLIC ORDINAL ;AN000;


; INPUT: (DOS COMMAND LINE PARAMETERS)

;	      [d:][path] TREE [D:][path] [/F] [/A]

;	 WHERE
;	      [d:][path] - Path where the TREE command resides.

;	      [D:][path] - Display of subdirectories starts with this
;			   specified subdirectory.  If this is not
;			   specified, the default is the drive root directory.

;	      [/F]	 - This requests the files in each subdirectory
;			   in addition to the subdirectories themselves
;			   are to be listed.

;	      [/A]	 - This requests use of alternate graphic chars
; = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
	      HEADER <PARSE CONTROL BLOCKS DEFINING PARMS> ;AN000;
;INPUT PARAMETERS CONTROL BLOCK, POINTED TO BY ES:DI WHEN CALLING PARSER

PARMS	      LABEL BYTE   ;AN000;PARMS CONTROL BLOCK
	      DW   PARMSX  ;AN000;POINTER TO PARMS EXTENSION
	      DB   0	   ;AN000; NUMBER OF STRINGS (0, 1, 2)
			   ; NEXT LIST WOULD BE EXTRA DELIM LIST
			   ;  (,& WHITESPACE ALWAYS)
			   ; NEXT LIST WOULD BE EXTRA END OF LINE LIST
			   ;  (CR,LF,0 ALWAYS)

PARMSX	      LABEL BYTE   ;AN000;PARMS EXTENSION CONTROL BLOCK
	      DB   0,1	   ;AN000; MIN, MAX POSITIONAL OPERANDS ALLOWED
	      DW   CONTROL_POS ;AN000; DESCRIPTION OF POSITIONAL 1

	      DB   1	   ;AN000; MAX SWITCH OPERANDS ALLOWED
	      DW   CONTROL_SW ;AN000; DESCRIPTION OF SWITCH 1

	      DB   0	   ;AN000; MAX KEYWORD OPERANDS ALLOWED
			   ; THERE IS NO CONTROL BLOCK
			   ;  DEFINING KEYWORDS

; = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =

;PARSER CONTROL BLOCK DEFINING THE ONLY POSITIONAL PARAMETER, OPTIONAL

;FIRST POSITIONAL PARAMETER IS:
;	[D:][PATH]

CONTROL_POS   LABEL BYTE   ;AN000;FIRST POSITIONAL DESCRIPTOR FOR FILESPEC,
			   ; OPTIONAL
	      DW   0201H   ;AN000; CONTROLS TYPE MATCHED
			   ; SELECTED BITS: "FILE SPEC" AND "OPTIONAL"

			   ; 8000H=NUMERIC VALUE, (VALUE LIST WILL BE CHECKED)
			   ; 4000H=SIGNED NUMERIC VALUE (VALUE LIST WILL BE
			   ;   CHECKED)
			   ; 2000H=SIMPLE STRING(VALUE LIST WILL BE CHECKED)
			   ; 1000H=DATE STRING (VALUE LIST WON'T BE CHECKED)
			   ; 0800H=TIME STRING (VALUE LIST WON'T BE CHECKED)
			   ; 0400H=COMPLEX LIST (VALUE LIST WON'T BE CHECKED)
			   ; 0200H=FILE SPEC (VALUE LIST WON'T BE CHECKED)
			   ; 0100H=DRIVE ONLY (VALUE LIST WON'T BE CHECKED)
			   ; 0080H=QUOTED STRING (VALUE LIST WON'T BE CHECKED)
			   ; 0010H=IGNORE ":" AT END IN MATCH
			   ; 0002H=REPEATS ALLOWED
			   ; 0001H=OPTIONAL

	      DW   0001H   ;AN000;FUNCTION_FLAGS
			   ; 0001H=CAP RESULT BY FILE TABLE
			   ; 0002H=CAP RESULT BY CHAR TABLE
			   ; 0010H=REMOVE ":" AT END
	      DW   RESULT1 ;AN000; RESULT BUFFER
	      DW   NOVALS  ;AN000; VALUE LISTS
	      DB   0	   ;AN000; NUMBER OF KEYWORD/SWITCH SYNONYMS
			   ;   IN FOLLOWING LIST


NOVALS	      LABEL BYTE   ;AN000;
	      DB   0	   ;AN000; NUMBER OF VALUE DEFINITIONS (0 - 3)

RESULT1       LABEL BYTE   ;AN000; BELOW FILLED IN FOR DEFAULTS
	      DB   5	   ;AN000; TYPE RETURNED: 0=RESERVED,
			   ;	   1=NUMBER, 2=LIST INDEX,
			   ;	   3=STRING, 4=COMPLEX,
			   ;	   5=FILESPEC, 6=DRIVE
			   ;	   7=DATE, 8=TIME
			   ;	   9=QUOTED STRING
	      DB   0FFH    ;AN000; MATCHED ITEM TAG
	      DW   0	   ;AN000;POINTER TO SYNONYM

RESULT_PTR1   DD   ?	   ;AN000; OFFSET OF STRING VALUE


; = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =

;PARSER CONTROL BLOCK DEFINING THE SWITCHES, OPTIONAL

;THE SWITCH IS "/F".  WHEN REQUESTED, IT MEANS TO LIST ALL FILE
;NAMES IN EVERY DIRECTORY BEING TRACED.
;THE OTHER SWITCH IS "/A". IT MEANS TO USE THE ALTERNATE SET OF GRAPHIC CHARS.

CONTROL_SW    LABEL BYTE   ;AN000;SWITCH DESCRIPTOR
	      DW   0000H   ;AN000; CONTROLS TYPE MATCHED
			   ; 8000H=NUMERIC VALUE, (VALUE LIST WILL BE CHECKED)
			   ; 4000H=SIGNED NUMERIC VALUE (VALUE LIST WILL BE
			   ;   CHECKED)
			   ; 2000H=SIMPLE STRING(VALUE LIST WILL BE CHECKED)
			   ; 1000H=DATE STRING (VALUE LIST WON'T BE CHECKED)
			   ; 0800H=TIME STRING (VALUE LIST WON'T BE CHECKED)
			   ; 0400H=COMPLEX LIST (VALUE LIST WON'T BE CHECKED)
			   ; 0200H=FILE SPEC (VALUE LIST WON'T BE CHECKED)
			   ; 0100H=DRIVE ONLY (VALUE LIST WON'T BE CHECKED)
			   ; 0080H=QUOTED STRING (VALUE LIST WON'T BE CHECKED)
			   ; 0010H=IGNORE ":" AT END IN MATCH
			   ; 0002H=REPEATS ALLOWED
			   ; 0001H=OPTIONAL

	      DW   0002H   ;AN000;FUNCTION_FLAGS
			   ; 0001H=CAP RESULT BY FILE TABLE
			   ; 0002H=CAP RESULT BY CHAR TABLE
			   ; 0010H=REMOVE ":" AT END

	      DW   RESULTSW1 ;AN000; RESULT BUFFER
	      DW   NOVALS  ;AN000; VALUE LISTS
	      DB   2	   ;AN002; NUMBER OF KEYWORD/SWITCH SYNONYMS
			   ;   IN FOLLOWING LIST
F_SW	      DB   "/F",0  ;AN000; IF n >0, KEYWORD 1
A_SW	      DB   "/A",0  ;AN002; IF n >0, KEYWORD 2



RESULTSW1     LABEL BYTE   ;AN000; BELOW FILLED IN FOR DEFAULTS
	      DB   3	   ;AN000; TYPE RETURNED: 0=RESERVED,
			   ;	   1=NUMBER, 2=LIST INDEX,
			   ;	   3=STRING, 4=COMPLEX,
			   ;	   5=FILESPEC, 6=DRIVE
			   ;	   7=DATE, 8=TIME
			   ;	   9=QUOTED STRING
	      DB   0FFh    ;AN000; MATCHED ITEM TAG

SYNONYM       DW   0	   ;AN000; SYNONYM POINTER (BASED ON ES:)
RESULT_PTR2   DD   ?	   ;AN000; OFFSET OF STRING VALUE
	      PATHLABL TREEPAR ;AN013;
; =  =	=  =  =  =  =  =  =  =	=  =
	      HEADER <PARSER - DRIVE SYSPARSE, VERIFY RESULTS> ;AN000;
;  $SALUT (4,4,9,36)		   ;AN000;
PARSER PROC NEAR		   ;AN000;
   PUBLIC PARSER		   ;AN000;

;INPUT: "CURRENT_PARM" = OFFSET TO NEXT PARM IN COMMAND STRING
;	"ORDINAL" = COUNT OF NEXT PARM TO PARSE
;	"COMMAND" = TEXT OF DOS COMMAND LINE PARMS STRING
;OUTPUT: CARRY IS SET IF THERE WAS A PROBLEM, AX HAS PARSE RET CODE.
;	 CARRY IS CLEAR IF ALL OK WITH THE PARMS
;THE PSP IS NOT REFERENCED, SINCE THE PARMS HAVE BEEN MOVED OUT OF THERE.
; =  =	=  =  =  =  =  =  =  =	=  =

;  $SEARCH COMPLEX		   ;AN000;LOOP THRU COMMAND LINE
   JMP SHORT $$SS1
$$DO1:
       MOV  ORDINAL,CX		   ;AN000;SAVE UPDATED COUNT

				   ;LOOKING AT RETURN CODE IN AX,
				   ; JUST PRODUCED BY SYSPARSE...
       CMP  AX,ZERO		   ;AN000;WERE THERE ANY ERRORS?
;      $IF  NE			   ;AN000;HAD A PROBLEM FOUND BY SYSPARSE
       JE $$IF2
	   CALL PARSE_ERROR	   ;AN000;DISPLAY REASON FOR ERROR

	   STC			   ;AN000;SET CARRY TO INDICATE ERROR
;      $ELSE			   ;AN000;SINCE OK BY SYSPARSE
       JMP SHORT $$EN2
$$IF2:
	   MOV	CURRENT_PARM,SI    ;AN000;REMEMBER HOW FAR I GOT
	   CALL CHECK_PATH	   ;AN000;SEE IF A GOOD PATH WAS SPECIFIED
				   ;OUTPUT: CY SET IF ERROR
;      $ENDIF			   ;AN000;
$$EN2:
;  $EXITIF C,NUL		   ;AN000;HAD A PROBLEM WITH THE PARMS
   JC $$SR1

				   ;SINCE ALL OK SO FAR, CONTINUE
;  $STRTSRCH			   ;AN000;ENTRY POINT INTO THE SEARCH LOOP
$$SS1:
       LEA  DI,PARMS		   ;AN000; ES:DI = PARSE CONTROL DEFINITON
       MOV  SI,CURRENT_PARM	   ;AN000; DS:SI = COMMAND STRING, NEXT PARM
       XOR  DX,DX		   ;AN000; RESERVED, INIT TO ZERO
       MOV  CX,ORDINAL		   ;AN000; OPERAND ORDINAL, INITIALLY ZERO
       CALL SYSPARSE		   ;AN000;
				   ; AX=EXIT CODE
				   ; BL=TERMINATED DELIMITER CODE
				   ; CX=NEW OPERAND ORDINAL
				   ; SI=SET TO PAST SCANNED OPERAND
				   ; DX=SELECTED RESULT BUFFER
       CMP  AX,SYSPRM_EX_EOL	   ;AN000; IS THAT THE END OF THE PARMS?
				   ;IF NOT, LOOP BACK AND FIND OUT
				   ; WHAT THAT PARM IS
;  $ENDLOOP E			   ;AN000;END OF LIST
   JNE $$DO1
       CLC			   ;AN000;SAY ALL OK
;  $ENDSRCH			   ;AN000;
$$SR1:
   RET				   ;AN000;RETURN TO CALLER
PARSER ENDP			   ;AN000;
; =  =	=  =  =  =  =  =  =  =	=  =
   HEADER <CHECK_PATH - SEE IF THE PATH IS OK> ;AN000;
;MOVE THE PATH STRING FROM RESULT BUFFER TO "START_DRIVE" AND "START_PATH",
;VERIFY THE LENGTH OF THE PATH AS BEING WITHIN LIMITS.
;CHECK FOR THE /F SWITCH, SETTING "FLAGS" (F_SWITCH BIT ON) IF /F SPECIFIED.

;INPUT: DX AS SET BY SYSPARSE, POINTS TO RESULT BUFFER
;OUTPUT: CY SET IF PROBLEM, CY CLEAR IF ALL OK
; =  =	=  =  =  =  =  =  =  =	=  =

CHECK_PATH PROC NEAR		   ;AN000;
   PUBLIC CHECK_PATH		   ;AN000;

   MOV	BX,DX			   ;AN000;SET DATA BASE REG TO POINT TO THIS OPERAND
   CMP	BX,OFFSET RESULT1	   ;AN000;WAS PATH SPECIFIED?
;  $IF	E			   ;AN000;IF PATH SPECIFIED,
   JNE $$IF9
       MOV  SI,WORD PTR RESULT_PTR1 ;AN000;GET WHERE THE STRING IS
       CMP  BYTE PTR [SI]+1,COLON ;AN000;DOES PATH START WITH DRIVE?
;      $IF  E			   ;AN000;STARTS WITH DRIVE
       JNE $$IF10
	   LEA	DI,START_DRIVE	   ;AN000;MOVE PARM TO STARTUP FILESPEC
	   LODSB		   ;AN000;MOVE THE DRIVE ID
	   STOSB		   ;AN000; INTO "START_DRIVE"
	   INC	SI		   ;AN000;STEP SOURCE INDEX OVER COLON
	   INC	DI		   ;AN000;STEP DEST INDEX OVER COLON
;      $ELSE			   ;AN000;DOES NOT START WITH DRIVE
       JMP SHORT $$EN10
$$IF10:
	   LEA	DI,START_PATH	   ;AN000;MOVE PARM TO STARTUP FILESPEC
;      $ENDIF			   ;AN000;PATH HAVE DRIVE?
$$EN10:

       PUSH SI			   ;AN012;SAVE WHERE STRING STARTS
       CALL SCAN_DBCS		   ;AN012;SCAN STRING FOR DBCS
				   ;DL=LAST CHAR, DH=NEXT TO LAST CHAR
       POP  SI			   ;AN012;RESTORE POINTER TO START OF STRING
				   ;NOW TO GET THE PATH ITSELF

       MOV  CX,MAX_PATH 	   ;AN000;SET THE LIMIT OF PATH LENGTH
       INC  CX			   ;AN000; INCLUDING THE NUL AT THE END
;      $SEARCH COMPLEX		   ;AN000;
       JMP SHORT $$SS13
$$DO13:
	   STOSB		   ;AN000;PUT THIS CHAR INTO "START_PATH"
;      $STRTSRCH		   ;AN000;
$$SS13:
	   LODSB		   ;AN000;GET A CHAR FROM PARSED STRING
	   CMP	AL,NUL		   ;AN000;IS THIS THE DELIMITER?
;      $EXITIF E		   ;AN000;NORMAL END OF STRING FOUND
       JNE $$IF13
	   CMP	DL,BACK_SLASH	   ;AN012;IS PREV CHAR A BACKSLASH?
;	   $IF	E,AND		   ;AN012;YES, PREV CHAR WAS A BACKSLASH
	   JNE $$IF16
	   CMP	DH,BACK_SLASH	   ;AN012;IS CHAR BEFORE THAT A BACKSLASH?
;	   $IF	NE,AND		   ;AN012;NO, CHAR BEFORE THAT WAS NOT A BACKSLASH
	   JE $$IF16
	   CMP	CX,MAX_PATH	   ;AN000;WAS THIS THE ONLY CHAR?
;	   $IF	NE		   ;AN000;NO, NOT THE ONLY ONE
	   JE $$IF16
	       MOV  BYTE PTR [DI-1],NUL ;AN000;CHANGE IT TO A "NUL"
;	   $ENDIF		   ;AN000;
$$IF16:
	   CLC			   ;AN000;FLAG NO ERROR
;      $ORELSE			   ;AN000;CHECK OUT THIS NEW CHAR
       JMP SHORT $$SR13
$$IF13:
;      $ENDLOOP LOOP		   ;AN000;GO BACK AND SAVE IT, IF ROOM
       LOOP $$DO13
	   LEA	DI,MSGNUM_INVPATH  ;AN000;"INVALID PATH"
	   CALL SENDMSG 	   ;AN000;DISPLAY THE MESSAGE

	   STC			   ;AN000;FLAG AN ERROR
;      $ENDSRCH 		   ;AN000;
$$SR13:

;  $ELSE			   ;AN000;FILESPEC NOT SPECIFIED
   JMP SHORT $$EN9
$$IF9:
       MOV  AX,SYNONYM		   ;AN002;GET SYNONYM POINTER
       CMP  AX,OFFSET F_SW	   ;AN002;WAS THE SWITCH /F?
;      $IF  E			   ;AN002;IF /F
       JNE $$IF22
	   MOV	F_SW,BLANK	   ;AN003;STRIKE THE /F FROM THE LIST OF SWITCHES
	   OR	FLAGS,F_SWITCH	   ;AN000;REQUEST LISTING OF FILENAMES
	   CLC			   ;AN000;NO ERROR
;      $ELSE			   ;AN002;SINCE NOT /F, MUST BE /A
       JMP SHORT $$EN22
$$IF22:
	   MOV	A_SW,BLANK	   ;AN003;STRIKE THE /A FROM THE LIST OF SWITCHES
	   MOV	AX,WORD PTR GRAF_TABLE_ALT ;AN002;PICK UP THE ALTERNATE SET
	   MOV	WORD PTR GRAF_TABLE,AX ;AN002; OF GRAPHICS CHARACTERS
	   MOV	AX,WORD PTR GRAF_TABLE_ALT+WORD ;AN002; AND MOVE THEM TO
	   MOV	WORD PTR GRAF_TABLE+WORD,AX ;AN002; THE TABLE OF GRAPHICS TO BE USED
;      $ENDIF			   ;AN002;
$$EN22:
;  $ENDIF			   ;AN000;FILESPEC?
$$EN9:
   RET				   ;AN000;RETURN TO CALLER
CHECK_PATH ENDP 		   ;AN000;
; =  =	=  =  =  =  =  =  =  =	=  =
   HEADER <PARSE_ERROR - DISPLAY ERROR MSG FOR PARSER> ;AN000;
PARSE_ERROR PROC NEAR		   ;AN000;
   PUBLIC PARSE_ERROR		   ;AN000;

;INPUT: AX - ERROR NUMBER RETURNED FROM PARSE.
;	SI - OFFSET INTO COMMAND OF FIRST BYTE BEYOND PARM IN ERROR
;	"CURRENT_PARM" - OFFSET INTO COMMAND OF WHERE TO START LOOKING FOR PARM
; =  =	=  =  =  =  =  =  =  =	=  =

   MOV	MSGNUM_PARSE,AX 	   ;AN000;SET THE ERROR NUMBER
   MOV	AX,CURRENT_PARM 	   ;AN004;GET POINTER TO START OF BAD PARM
   CMP	SI,AX			   ;AN004;HAS THE INDEX TO COMMAND LINE MOVED?
;  $IF	NE			   ;AN004;YES, THERE IS A FAULTY PARM
   JE $$IF26
       MOV  BYTE PTR [SI],NUL	   ;AN004;DELIMIT THE BAD PARM
       MOV  SUBLIST_PARSE.SUB_VALUE,AX ;AN000;POINT SUBLIST TO BAD PARM

       MOV  MSGNUM_PARSE.MSG_SUBLIST,OFFSET SUBLIST_PARSE ;AN004;POINT TO SUBLIST
       MOV  MSGNUM_PARSE.MSG_COUNT,ONE_SUBS ;AN004;SET COUNT OF SUBLISTS TO ONE
;  $ENDIF			   ;AN004;INDEX MOVED?
$$IF26:
   LEA	DI,MSGNUM_PARSE 	   ;AN000;PASS MESSAGE DESCRIPTOR
   CALL SENDMSG 		   ;AN000;DISPLAY ERROR MESSAGE

   RET				   ;AN000;RETURN TO CALLER
PARSE_ERROR ENDP		   ;AN000;
; =  =	=  =  =  =  =  =  =  =	=  =
   PATHLABL TREEPAR		   ;AN013;
CSEG ENDS			   ;AN000;
   END				   ;AN000;
